#include "master.h"
#include <shellapi.h>
#include <shlwapi.h>
#include <dshow.h>
#include <commctrl.h>
#include <msxml2.h>
#include <shlobj.h>
#include "stream.h"
#include "gui.h"
#include "misc.h"
#include "playlist.h"
#include "systray.h"
#include "flags.h"
#include "metaparse.h"
#include "menu.h"
#include "comfunct/comfunct.h"

LRESULT StopStream(HWND hwnd, short *sOptions, REFERENCE_TIME rtStartTime)
{
    extern bool bCanSeek;
	extern IMediaSeeking *pSeek;
	extern IMediaControl *pControl;
	TCHAR* szAudioStatusText = GetStatusText(hwnd, 0);
     
     if(_tcscmp(szAudioStatusText, GetLocalText(83)) == 0) /* Downloading */
     {
         StopInternetDownload();
     }
     else
     {
         OAFilterState fsState;
		 REFERENCE_TIME rtTimeNow;
         pControl->lpVtbl->GetState(pControl, 10, &fsState);
		 if(SUCCEEDED(pControl->lpVtbl->Stop(pControl)))
		 {
			 KillTimer(hwnd, IDT_TIMETICK);
			 *sOptions &= (~(TIMER_ON));
		 }
		 pSeek->lpVtbl->SetPositions(pSeek, &rtStartTime, AM_SEEKING_AbsolutePositioning,
                                     NULL, AM_SEEKING_NoPositioning);
		 pSeek->lpVtbl->GetCurrentPosition(pSeek, &rtTimeNow);
		 SetStatus(hwnd, IDI_STATUS, 0, GetLocalText(37));
		 SendDlgItemMessage(hwnd, IDI_SLIDER, TBM_SETPOS, true, 0);
		 if(bCanSeek == true)
		 {
			 ElapsedTimeUpdate(hwnd, rtTimeNow);
		 }  
	     if(fsState == State_Paused)
		 {
			 SetDlgItemText(hwnd, IDI_CONT_PAUSE, GetLocalText(2));
         }
    }
	free(szAudioStatusText);
	MSNCheckAndUpdate(hwnd, NULL, true);
	UpdateTrayToolTip(hwnd);
	return 0;
}

LRESULT TogglePause(HWND hwnd, short* sOptions, bool bMediaKeyPlay)
{
    OAFilterState fsState;
	extern bool bCanSeek;
	extern IMediaControl *pControl;
    pControl->lpVtbl->GetState(pControl, 10, &fsState);
    if(fsState == State_Running)
    {
        if(SUCCEEDED(pControl->lpVtbl->Pause(pControl)))
        {
            if(bCanSeek == true)
            {
                KillTimer(hwnd, IDT_TIMETICK);
                *sOptions &= (~(TIMER_ON));
            }
            SetStatus(hwnd, IDI_STATUS, 0, GetLocalText(38));
            SetDlgItemText(hwnd, IDI_CONT_PAUSE, GetLocalText(12));
        }
    }    
    else if(fsState == State_Paused || bMediaKeyPlay == true)
    {
        if(SUCCEEDED(pControl->lpVtbl->Run(pControl)));
        {
            if(bCanSeek == true)
            {
                SetTimer(hwnd, IDT_TIMETICK, 1000, (TIMERPROC)NULL);
                *sOptions |= TIMER_ON;
            }
            SetDlgItemText(hwnd, IDI_CONT_PAUSE, GetLocalText(2));
            SetStatus(hwnd, IDI_STATUS, 0, GetLocalText(39));
        }                            
    }
    UpdateTrayToolTip(hwnd);
    return 0;
}

LRESULT PlayLocalFile(HWND hwnd, bool bTrayed, LPTSTR szFilePath)
{
    if(PathFileExists(szFilePath) == false)
	{
		ErrorMessage(GetLocalText(40));
		return 0;
	}
						    
	if(GetPlaylistType(szFilePath) != PLAYLIST_ERROR)
	{
        SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDI_PLAYLIST_COMMANDLINE, 0), (LPARAM)szFilePath);
    }
    else if(IsFileAudio(szFilePath) == false)
    {
        ErrorMessage(GetLocalText(41));
    }
    else
    {
        ProcessFile(hwnd, bTrayed, szFilePath, NULL);
    }
	return 0;
}

LRESULT PlayNonMP3URL(HWND hwnd, LPTSTR szFilePath, HANDLE* hDownloadedStream, DWORD capable)
{
    WCHAR* WideFilePath = NULL;
    HRESULT hr = 0;
	extern bool bCanSeek;
	extern IMediaSeeking *pSeek;
	extern IGraphBuilder *pGraph;
	extern IMediaControl *pControl;
	if(pGraph == NULL)
    {
        DShowInit();
	}
#ifndef UNICODE /* we're doing the same unicode conversion hack as elsewhere */

    WideFilePath = UnicodeConversion(szFilePath);
    hr = pGraph->lpVtbl->RenderFile(pGraph, WideFilePath, NULL);
    FreePointer(WideFilePath);
                                  
#else          
    
    hr = pGraph->lpVtbl->RenderFile(pGraph, szFilePath, NULL);
                                  
#endif /* end of !UNICODE 'if' */
    
    if(FAILED(hr))
    {
        ErrorMessage(GetLocalText(42));
        HRErrorInfo(hr);
        CloseStream(hwnd, hDownloadedStream);
        return 0;
    }
	if(_tcsicmp(PathFindExtension(szFilePath), TEXT(".ogg")) == 0)
	{
	    bCanSeek = false; /* Finding the file duration isn't implemented in all ogg codecs
						     If we continue to try and seek and it isn't implemented, we'll get 
							 a divide by zero exception */
	}
	else
    {
	    bCanSeek = (S_OK == pSeek->lpVtbl->CheckCapabilities(pSeek, &capable));
	}
    FileOpen(hwnd, szFilePath, bCanSeek);
    hr = 0;
    hr = pControl->lpVtbl->Run(pControl); /* This just tests to see if we can play the file and error out if not */
    if(FAILED(hr))
    {
        ErrorMessage(GetLocalText(41));
        HRErrorInfo(hr);
        CloseStream(hwnd, hDownloadedStream);
        return 0;
    }
    pControl->lpVtbl->Stop(pControl);
    PostMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDI_CONT_PLAY, 0), (LPARAM)NULL);
    return 0;
}

LRESULT PrepareAndPlayMP3Stream(HWND hwnd, LPARAM lParam, bool bTrayed, HANDLE* hDownloadedStream)
{
    const size_t sMaxLen = (MAX_PATH * sizeof(TCHAR));
	TCHAR* szAudioFile = malloc(sMaxLen);
	HMENU hParentMenu = GetMenu(hwnd), hOpenMenu = NULL, hControlMenu = NULL;

	CopyMemory(szAudioFile, (LPVOID)lParam, sMaxLen);
	hOpenMenu = GetSubMenu(hParentMenu, FILE_MENU);
	EnableMenuItem(hParentMenu, IDI_FILE_SAVESTREAM, MF_BYCOMMAND | MF_ENABLED);
	ToggleButton(hwnd, true, false);

	hControlMenu = GetSubMenu(hParentMenu, CONTROL_MENU);
    EnableMenuItem(hControlMenu, IDI_CONT_PAUSE, MF_BYCOMMAND | MF_ENABLED);
    EnableMenuItem(hControlMenu, IDI_CONT_PLAY, MF_BYCOMMAND | MF_ENABLED);
	DrawMenuBar(hwnd);

	ProcessFile(hwnd, bTrayed, szAudioFile, NULL);
			
	if(*hDownloadedStream != NULL)
	{
        CloseHandle(*hDownloadedStream);
    }

	*hDownloadedStream = CreateFile(szAudioFile, GENERIC_READ | DELETE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL);
	if(*hDownloadedStream == NULL || *hDownloadedStream == INVALID_HANDLE_VALUE)
    {
        ErrorInfo();
        ErrorMessage(GetLocalText(43));
        free(szAudioFile);
        CloseStream(hwnd, hDownloadedStream);
        return 1;
    }
    SaveAudioStream(*hDownloadedStream, NULL);
    free(szAudioFile);
    return 0;
}

LRESULT ParseDroppedFile(HWND hwnd, WPARAM wParam, PLAYLISTDATA* pld)
{
    HDROP hFilesInfo = NULL;
	extern IGraphBuilder *pGraph;
    unsigned long lFileCount = 0L;
    TCHAR szFileName[MAX_PATH] = {0};
	HCURSOR hWait = LoadCursor(NULL, IDC_WAIT), hArrow = LoadCursor(NULL, IDC_ARROW);
                 
    SetCursor(hWait);
	hFilesInfo = (HDROP)wParam;
    lFileCount = DragQueryFile(hFilesInfo, 0xFFFFFFFF, NULL, 0);

	if(pGraph != NULL)
    {
        SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDI_FILE_CLOSE, 0), (LPARAM)NULL);
    }
	
	if(lFileCount == 1L)
    {
        DragQueryFile(hFilesInfo, 0, szFileName, MAX_PATH);
		CommandLineOpen(szFileName, hwnd);
    }
	else
	{
		unsigned long lLoopCounter = 0L;
		size_t s_tStrlen = 0;
		TCHAR szBuffer[MAX_PATH] = TEXT("");
		HWND hPlaylistItems = GetDlgItem(hwnd, IDI_PLAYLIST_VIEW);
		DWORD dwThreadId = 0;

		pld->PlaylistItems = malloc(lFileCount * sizeof(TCHAR*));
		pld->lNumOfFilesinPlaylist = lFileCount;
		SetStatus(hwnd, IDI_STATUS, 0, GetLocalText(44));
		for(; lLoopCounter < lFileCount; ++lLoopCounter)
		{
			DragQueryFile(hFilesInfo, lLoopCounter, szBuffer, MAX_PATH);
			s_tStrlen = (_tcslen(szBuffer) + sizeof(TCHAR));
			pld->PlaylistItems[lLoopCounter] = malloc(s_tStrlen * sizeof(TCHAR));
			_tcscpy(pld->PlaylistItems[lLoopCounter], szBuffer);
		}

		StartPlaylist(pld, hwnd);
		CloseHandle(CreateThread(NULL, 0, BuildPlaylistView, (LPVOID)pld, 0, &dwThreadId));
	}    
    
    DragFinish(hFilesInfo);
	SetCursor(hArrow);
    return 0;
}

LRESULT LyricsHandler(HWND hwnd)
{
    TCHAR szFile[MAX_PATH] = TEXT("");
	GetWindowText(GetDlgItem(hwnd, IDI_FILENAME), szFile, MAX_PATH);
	DisplayLyrics(hwnd, szFile);
       
    return 0;
}

LRESULT NotifyMessage(HWND hwnd, LPARAM lParam, PLAYLISTDATA* pld, short sOptions)
{
	LPNMHDR lpnmHdr = (LPNMHDR)lParam;
	switch(lpnmHdr->code)
	{
		case NM_DBLCLK:
		{
			NMITEMACTIVATE nmItem = *(NMITEMACTIVATE*)lParam;
			LVITEM lvi = {LVIF_PARAM}; //Find the item and get its' LPARAM value to use to index pld
			lvi.iItem = nmItem.iItem;
			ListView_GetItem(lpnmHdr->hwndFrom, &lvi);
			pld->lCurrentPlayingFile = lvi.lParam;
			CloseStream(hwnd, NULL);
			ProcessFile(hwnd, sOptions & IS_TRAYED, pld->PlaylistItems[lvi.lParam], pld);
		}
		break;
		case NM_RCLICK:
		{
			POINT pt = {0};
			GetCursorPos(&pt);
			DestroyMenu(MakePViewMenu(hwnd, pt));
		}
		break;
	}
	return 0;
}

LRESULT PlayFolder(HWND hwnd, PLAYLISTDATA* pld)
{
	BROWSEINFO bi = {0};
	LPITEMIDLIST pid = NULL;
	TCHAR szPattern[MAX_PATH] = TEXT("");
	WIN32_FIND_DATA wfd = {0};
	HANDLE hFile = NULL;
	unsigned long lFileCount = 0;
	extern IGraphBuilder *pGraph;
	
	bi.lpszTitle = GetLocalText(45);
	bi.hwndOwner = hwnd;

	pid = SHBrowseForFolder(&bi);
	if(pid == NULL)
	{
		return 1;
	}
	SHGetPathFromIDList(pid, szPattern);
	SetStatus(hwnd, IDI_STATUS, 0, GetLocalText(44));
	_tcscat(szPattern, TEXT("\\*.*"));

	if(pGraph != NULL)
	{
		SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDI_FILE_CLOSE, 0), 0);
	}

	hFile = FindFirstFile(szPattern, &wfd);
	while(FindNextFile(hFile, &wfd) != 0)
	{
		/* not interested in any directories */
		if(wfd.cFileName[0] == TEXT('.') || (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
		{
			continue;
		}
		++lFileCount;
	}
	FindClose(hFile);
	pld->lNumOfFilesinPlaylist = lFileCount;
	pld->PlaylistItems = malloc(lFileCount * sizeof(TCHAR*));
	
	FolderFilesToPlaylist(szPattern, pld);
	return 0;
}

#ifdef UNICODE

LRESULT AppCommand(HWND hwnd, LPARAM lParam)
{
	short dwCommand = ((short)(HIWORD(lParam) & ~0xF000)); //GET_APPCOMMAND_LPARAM(lParam) not defined in MinGW Win32API 3.6
	switch(dwCommand)
	{
		/*avoiding more icky ifdef's here by just using the number since some of these are only defines for XPSP1 or above */
		case 46: /* APPCOMMAND_MEDIA_PLAY */
		{
			SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDI_CONT_PLAY, 0), 0);
		}
		break;
		case 47: /* APPCOMMAND_MEDIA_PAUSE */
		case 14: /*APPCOMMAND_MEDIA_PLAY_PAUSE */
		{
			SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDI_CONT_PAUSE, 0), 0);
		}
		break;
		case 13: /* APPCOMMAND_MEDIA_STOP */
		{
			SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDI_CONT_STOP, 0), 0);
		}
		break;
		case 11: /* APPCOMMAND_MEDIA_NEXTTRACK */
		{
			SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDI_PLAYLIST_NEXT, 0), 0);
		}
		break;
		case 8: /* APPCOMMAND_VOLUME_MUTE */
		{
			SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDI_VOL_MUTE, 0), 0);
		}
		break;
	}
	return TRUE;
}

LRESULT ToggleHook(HWND hwnd, short* sOptions)
{
	static HHOOK hMediaKeyHook = NULL;
	if(!(*sOptions & MEDIA_HOOK))
	{
		HMODULE hComFunct = GetModuleHandle(TEXT("comfunct.dll"));
        HOOKPROC MultiMediaHook = (HOOKPROC)GetProcAddress(hComFunct, "MultiMediaKeyHook");
        MenuCheck(hwnd, TOOLS_MENU, IDI_TOOLS_MEDIAHOOK, true);
		*sOptions |= MEDIA_HOOK;
		hMediaKeyHook = SetWindowsHookEx(WH_KEYBOARD_LL, MultiMediaHook, hComFunct, 0);
	}
	else
	{
		MenuCheck(hwnd, TOOLS_MENU, IDI_TOOLS_MEDIAHOOK, false);
		UnhookWindowsHookEx(hMediaKeyHook);
		*sOptions &= (~(MEDIA_HOOK));
	}
	return 0;
}

#endif
